package com.binc.testspring.common.utils;

import com.binc.testspring.common.annotation.CompareFiled;
import com.binc.testspring.dto.Student;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.PropertyUtils;
import org.junit.Test;

import javax.validation.constraints.NotNull;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 *
 * Autho: binC
 * Date:  2021/11/3 10:34
 * Description: 一个特殊用处的工具；记录对象前后变换值的，方便存日志
 *
 * <p> {公司名称}从{测试广西优居科技有限公司1123}变为{测试广西优居科技有限公司1}；  结果是这样的样式</>
 *
 */
@Slf4j
public class CompareUtils {


        /**
         * 将要比较的字段<"字段描述":"字段值">放入到Map中；
         *
         * @param obj
         * @return
         */
        public static Map<String, String> setValueToMap(@NotNull Object obj) {
        Map<String, String> iMap = Maps.newHashMap();
        Field[] fields = obj.getClass().getDeclaredFields();
        Arrays.asList(fields).forEach(i -> {
            String filedName = i.getName();
            if (PropertyUtils.isReadable(obj, filedName) && PropertyUtils.isWriteable(obj, filedName)) {
                if (i.isAnnotationPresent(CompareFiled.class)) {  // 这是一个自定义注解，标识对象中那些字段参与对比；并且标注字段名
                    CompareFiled compareFiled = i.getAnnotation(CompareFiled.class);
                    iMap.put(compareFiled.name(), getFieldByClasss(filedName, obj));
                }
            }
        });
        return iMap;
    }


        /**
         * 根据属性名获取属性元素
         *
         * @param fieldName
         * @param object
         * @return
         */
        private static String getFieldByClasss(String fieldName, Object object) {
        Class<?> clazz = object.getClass();
        for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
            try {
                Field field = clazz.getDeclaredField(fieldName);
                field.setAccessible(true);
                String filedType = field.getGenericType().toString();
                if ("class java.lang.Double".equals(filedType)) {
                    DecimalFormat df = new DecimalFormat("######0.00");
                    Double num = (Double) Optional.ofNullable(field.get(object)).orElseGet(() -> 0.00);
                    return df.format(num);
                }
                if ("class java.math.BigDecimal".equals(filedType)) {
                    BigDecimal bd = new BigDecimal(Optional.ofNullable(field.get(object)).orElseGet(() -> 0.00).toString());
                    bd = bd.setScale(2, BigDecimal.ROUND_HALF_UP);
                    return bd.toString();
                }
                return Optional.ofNullable(field.get(object)).orElseGet(String::new).toString();
            } catch (Exception e) {
                log.info(fieldName + ": " + e.getMessage());
            }
        }
        return null;
    }

        /**
         * 比较对象属性值
         *
         * @param newMap
         * @param oldMap
         * @return
         */
        public static String mapDiff(Map<String, String> newMap, Map<String, String> oldMap) {
        if (newMap == null || oldMap == null) {
            return null;
        }
        Set<Map.Entry<String, String>> setNewMap = newMap.entrySet();
        Set<Map.Entry<String, String>> setOldMap = oldMap.entrySet();
        StringBuilder logSb = new StringBuilder();
//        StringBuilder oldSb= new StringBuilder();
        setNewMap.stream().flatMap(x -> setOldMap.stream().
                        filter(y -> {
                            String newValue = Optional.ofNullable(x.getValue()).orElseGet(String::new).trim();
                            String oldValue = Optional.ofNullable(y.getValue()).orElseGet(String::new).trim();
                            if (x.getKey().equals(y.getKey()) && !newValue.equals(oldValue)) {
                                logSb.append("{" + x.getKey() + "}").append("从").append("{" + oldValue + "}").append("变为").append("{" + newValue + "}").append("；");
//                        oldSb.append(y.getKey()).append(":").append(oldValue).append("；");
                            }
                            return true;
                        })
        ).collect(Collectors.toList());
        return String.format("%s", logSb.toString());
    }

    /**
     * 对比老旧对象，将变化存成一个字符串，方便记录日志；
     *
     * <p>格式：{公司名称}从{测试广西优居科技有限公司1123}变为{测试广西优居科技有限公司1}；</>
     * @param newObj
     * @param oldObj
     * @return
     */
    public static String mapDiff(@NotNull Object oldObj,@NotNull Object newObj){
        Map<String, String> oldDto = setValueToMap(oldObj);
        Map<String, String> newDto = setValueToMap(newObj);
        String logRemark = mapDiff(newDto, oldDto);
        return logRemark;
    }

    //示例
    @Test
    public void test(){
        Student oldStudent = Student.builder().id(1L)
                .name("张山")
                .age(18).build();
        Student newStudent = Student.builder().id(2L)
                .name("张山2")
                .age(182).build();
        String s = CompareUtils.mapDiff( oldStudent,newStudent);
        System.out.println(s);
        //{姓名}从{张山}变为{张山2}；{年龄}从{18}变为{182}；
        // 因为id属性没有标注@compareFiled,所以id的变化是不记录的；
    }

}
